package hc.core.util;

import hc.core.ContextManager;
import hc.core.EventCenter;
import hc.core.IConstant;
import hc.core.IContext;
import hc.core.IEventHCListener;
import hc.core.Message;
import hc.core.MsgBuilder;
import hc.core.RootServerConnector;
import hc.core.sip.SIPManager;

import java.util.Random;

public class CUtil {

	public static void xor(final byte[] src, final int offset, final int len, final byte[] keys){
		final int k_len = keys.length;
		final int endIdx = offset + len;
		int modeK = 0;
		for (int i = offset; i < endIdx; i++) {
			src[i] ^= keys[modeK++];
			if(modeK == k_len){
				modeK = 0;
			}
		}
	}
	
	public static void generateRandomKey(final byte[] data, final int offset, final int len){
		final Random r = new Random(System.currentTimeMillis());
		
		for (int i = offset, endIdx = offset + len; i < endIdx; i++) {
			data[i] = (byte) (r.nextInt() & 0xFF);
		}
	}
	
	/**
	 * 将新的CertKey用母密进行加密，加密后全长为TRANS_CERT_KEY_LEN
	 * @param certKey
	 * @return
	 */
	public static void generateTransCertKey(final byte[] data, final int offset, final byte[] certKey, final byte[] password){
		final int index = TRANS_CERT_KEY_START_IDX + offset;
		generateRandomKey(data, index, TRANS_CERT_KEY_LEN);
		
		for (int i = 0, j = index; i < certKey.length; i++, j++) {
			data[j] = certKey[i];
		}
		xor(data, index, TRANS_CERT_KEY_LEN, password);
		
		//注意与普通数据加解密的次序相反
		if(userEncrypter != null){
			userEncrypter.encryptCertKey(data, index, TRANS_CERT_KEY_LEN);
		}
	}
	
	/**
	 * 将新收到的加密后的CertKey，进行解密还原
	 * @param ts
	 * @param offset
	 * @param length
	 * @return
	 */
	public static void decodeFromTransCertKey(final byte[] ts, final int offset, final byte[] password, final byte[] storebs){
		final int index = TRANS_CERT_KEY_START_IDX + offset;

		//注意与普通数据加解密的次序相反
		if(userEncrypter != null){
			userEncrypter.decryptCertKey(ts, index, TRANS_CERT_KEY_LEN);
		}
		
		xor(ts, index, TRANS_CERT_KEY_LEN, password);
		
		for (int i = 0, j = index; i < storebs.length; i++, j++) {
			storebs[i] = ts[j];
		}
	}
	
	public static final int TRANS_CERT_KEY_START_IDX = 28;
	public static final int VERIFY_CERT_IDX = 26;
	public static final int CERT_KEY_LEN = 64;
	
	//必须满足VERIFY_CERT_IDX + CERT_KEY_LEN <= TRANS_CERT_KEY_LEN;同时在发现最优MTU前，建议其小于140的最小UDP
	//参见：buildCheckCertKeyAndPwd
	public static final int TRANS_CERT_KEY_LEN = 99;
	
	public static boolean isSecondCertKeyError = false;
	public static byte[] SERVER_READY_TO_CHECK;
	
	//以下值请注意与RSConfig同步
	public static final String INI_CERTKEY = "*49AtBU7qtD:{&DJ7ey|&2S0.,Kjd4}9^1Y!id(12YUOSwR$d01u}[49AtBU7qtW";
	public static byte[] CertKey, OneTimeCertKey;
	
	public static final IEncrypter userEncrypter = loadEncrypter();
	
	private static IEncrypter loadEncrypter(){
		String encryptClass = (String)IConstant.getInstance().getObject("encryptClass");
		if(encryptClass != null){
			try {
				Class c = Class.forName(encryptClass);
				IEncrypter en = (IEncrypter)c.newInstance();
				en.setUUID(IConstant.uuidBS);
				en.setPassword(IConstant.passwordBS);
				en.initEncrypter(!IConstant.serverSide);
				
//				hc.core.L.V=hc.core.L.O?false:LogManager.log("Enable user Encrypter [" + encryptClass + "]");
				
				return en;
			} catch (Exception e) {
				LogManager.err("Error Load Encrypter [" + encryptClass + "]");
				e.printStackTrace();
			}
		}else{
//			hc.core.L.V=hc.core.L.O?false:LogManager.log("Disable user Encrypter");
		}
		return null;
	}
	
//	public static String getCode(byte[] bs){
//		String str1 = "";
//		for (int i = 0; i < bs.length; i++) {
//			str1 += " " + (Integer.toHexString(0xFF & bs[i]));
//		}
//		return str1;
//	}
	
	public static void buildCheckCertKeyAndPwd(final byte[] data, final int offset, final byte[] pwd, final byte[] certKey){
		final Random r = new Random(System.currentTimeMillis());
	
		final int endIdx = CUtil.VERIFY_CERT_IDX + CUtil.CERT_KEY_LEN;
		final int firstHalfEndIdx = CUtil.VERIFY_CERT_IDX + CUtil.CERT_KEY_LEN / 2;
		final int pwdLen = pwd.length;
	
//		String str1, str2;
//		str1 = "";
//		str2 = "";
		for (int i = 0; i < endIdx; i++) {
			int dataIdx = offset + i;
			if(i >= (CUtil.VERIFY_CERT_IDX)&& i < (endIdx)){
				int checkIdx = i - CUtil.VERIFY_CERT_IDX;
//				str1 += " " + (Integer.toHexString(0xFF & data[dataIdx]));
				if(i < (firstHalfEndIdx)){
					//用密码和CertKey进行双处理
					data[dataIdx] = (byte) (data[dataIdx] ^ pwd[checkIdx%pwdLen] ^ certKey[checkIdx]);
				}else{
					//仅用余下的CertKey进行单处理
					data[dataIdx] = (byte) (data[dataIdx] ^ certKey[checkIdx]);
				}
//				str2 += " " + (Integer.toHexString(0xFF & data[dataIdx]));
			}else{
				int g = r.nextInt();
				data[dataIdx] = (byte) (g & 0xFF);
			}
		}
//		L.V = L.O ? false : LogManager.log("Str1 : " + str1);
//		L.V = L.O ? false : LogManager.log("Str2 : " + str2);
	}


	static{
		
		if(IConstant.serverSide == false){
			
			//客户端环境
			EventCenter.addListener(new IEventHCListener(){
				public boolean action(final byte[] bs) {
					//并将该随机数发送给客户机，客户机用同法处理后回转给服务器
					CUtil.resetCheck();
					CUtil.SERVER_READY_TO_CHECK = ContextManager.cloneDatagram(bs);
					
					buildCheckCertKeyAndPwd(bs, MsgBuilder.INDEX_MSG_DATA, IConstant.passwordBS, CUtil.CertKey);
					//开启以下部分，不能测试通知，所以关闭以下段
					//注意与普通数据加解密的次序相反
					if(CUtil.userEncrypter != null){
						CUtil.userEncrypter.encryptCertKey(bs, MsgBuilder.INDEX_MSG_DATA, CUtil.TRANS_CERT_KEY_LEN);
					}

					byte[] sendBS = new byte[MsgBuilder.UDP_BYTE_SIZE];
					System.arraycopy(bs, MsgBuilder.INDEX_MSG_DATA, sendBS, MsgBuilder.INDEX_MSG_DATA, CUtil.TRANS_CERT_KEY_LEN);
					
					ContextManager.getContextInstance().send(MsgBuilder.E_RANDOM_FOR_CHECK_CK_PWD, sendBS, CUtil.TRANS_CERT_KEY_LEN);
					
					hc.core.L.V=hc.core.L.O?false:LogManager.log("Sended processed random data to check certification key and password back to server");
					
					return true;
				}

				public byte getEventTag() {
					return MsgBuilder.E_RANDOM_FOR_CHECK_CK_PWD;
				}});			
			
			EventCenter.addListener(new IEventHCListener(){
				public boolean action(final byte[] bs) {
					String status = Message.getMsgBody(bs, MsgBuilder.INDEX_MSG_DATA);
//					System.out.println("Status:" + status);
					if(status.equals(String.valueOf(IContext.BIZ_SERVER_AFTER_PWD_ERROR))){
						ContextManager.getContextInstance().doExtBiz(IContext.BIZ_SERVER_AFTER_PWD_ERROR, null);
					}else if(status.equals(String.valueOf(IContext.BIZ_SERVER_AFTER_CERTKEY_ERROR))){
						ContextManager.getContextInstance().doExtBiz(IContext.BIZ_SERVER_AFTER_CERTKEY_ERROR, null);
					}else if(status.equals(String.valueOf(IContext.BIZ_SERVER_AFTER_CERTKEY_AND_PWD_PASS))){
						LogManager.info("CertKey PWD are passed");
						ContextManager.getContextInstance().doExtBiz(IContext.BIZ_SERVER_AFTER_CERTKEY_AND_PWD_PASS, null);
						CUtil.resetCheck();
					}else if(status.equals(String.valueOf(IContext.BIZ_SERVER_AFTER_SERVICE_IS_FULL))){
						LogManager.info("service is full");
						ContextManager.getContextInstance().doExtBiz(IContext.BIZ_SERVER_AFTER_SERVICE_IS_FULL, null);
					}else if(status.equals(String.valueOf(IContext.BIZ_SERVER_AFTER_OLD_MOBI_VER_STATUS))){
						ContextManager.getContextInstance().doExtBiz(IContext.BIZ_SERVER_AFTER_OLD_MOBI_VER_STATUS, null);
					}else{
						LogManager.info("account locked or unknown");
						ContextManager.getContextInstance().doExtBiz(IContext.BIZ_SERVER_AFTER_UNKNOW_STATUS, null);
					}
					return true;
				}

				public byte getEventTag() {
					return MsgBuilder.E_AFTER_CERT_STATUS;
				}});
			
			EventCenter.addListener(new IEventHCListener(){
				public boolean action(final byte[] bs) {
					
					CUtil.decodeFromTransCertKey(bs, MsgBuilder.INDEX_MSG_DATA, 
							IConstant.passwordBS, CUtil.CertKey);
					
					IConstant.getInstance().setObject(IConstant.CertKey, CertKey);
					
					if(ContextManager.cmStatus == ContextManager.STATUS_CLIENT_SELF){
						//仅保存新的证书，并通知新消息事件，HCCtrlGame会获得通知，并UI提示
//						MsgNotifier.getInstance().notifyNewMsg("OK, update new cert!");
						
						//证书已送达
						HCURLUtil.sendCmd(HCURL.DATA_CMD_SendPara, HCURL.DATA_PARA_CERT_RECEIVED, "OK");
						return true;
					}
					LogManager.info("trans new CertKey");

					//重新发送密码
					buildCheckCertKeyAndPwd(CUtil.SERVER_READY_TO_CHECK, MsgBuilder.INDEX_MSG_DATA, IConstant.passwordBS, CUtil.CertKey);
					//开启以下部分，不能测试通知，所以关闭以下段
					//注意与普通数据加解密的次序相反
					if(CUtil.userEncrypter != null){
						CUtil.userEncrypter.encryptCertKey(CUtil.SERVER_READY_TO_CHECK, MsgBuilder.INDEX_MSG_DATA, CUtil.TRANS_CERT_KEY_LEN);
					}

					ContextManager.getContextInstance().send(MsgBuilder.E_RANDOM_FOR_CHECK_CK_PWD, 
							CUtil.SERVER_READY_TO_CHECK, CUtil.TRANS_CERT_KEY_LEN);
					
					//注意不能用resetCheck来进行回收，因为上行发送后会进行回收
					CUtil.SERVER_READY_TO_CHECK = null;
					
					hc.core.L.V=hc.core.L.O?false:LogManager.log("check certification key and password back to server AFTER New Cert Key");

					return true;
				}

				public byte getEventTag() {
					return MsgBuilder.E_TRANS_NEW_CERT_KEY;
				}});

		
			EventCenter.addListener(new IEventHCListener(){
				public boolean action(final byte[] bs) {
					LogManager.info(RootServerConnector.unObfuscate("og tnercpy tnotemi eeKy"));
					
					OneTimeCertKey = new byte[CUtil.CERT_KEY_LEN];
					CUtil.decodeFromTransCertKey(bs, MsgBuilder.INDEX_MSG_DATA, 
							IConstant.passwordBS, OneTimeCertKey);
//					L.V = L.O ? false : LogManager.log("OneTime : " + CUtil.getCode(OneTimeCertKey));
					SIPManager.notifyCertPwdPassAtClient();
					return true;
				}

				public byte getEventTag() {
					return MsgBuilder.E_TRANS_ONE_TIME_CERT_KEY;
				}});

		}
	}


	public static void resetCheck() {
		if(SERVER_READY_TO_CHECK != null){
			SERVER_READY_TO_CHECK = null;
			isSecondCertKeyError = false;
		}
	}

}
